"use client"

import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react"
import zhCNRaw from "@jjk/locales/zh-CN.json"

type LocaleCode = "zh-CN" | "en"

type MessageDict = Record<string, string>
type PhrasesMap = Record<string, string>

type I18nResources = Record<LocaleCode, MessageDict>

type I18nContextValue = {
  locale: LocaleCode
  setLocale: (locale: LocaleCode) => void
  t: (key: string, fallback?: string) => string
  messages: MessageDict
}

const I18N_STORAGE_KEY = "app.locale"

const I18nContext = createContext<I18nContextValue | null>(null)

function loadStoredLocale(): LocaleCode | null {
  if (typeof window === "undefined") return null
  try {
    const raw = window.localStorage.getItem(I18N_STORAGE_KEY)
    if (!raw) return null
    if (raw === "zh-CN" || raw === "en") return raw
    return null
  } catch {
    return null
  }
}

function saveStoredLocale(locale: LocaleCode) {
  if (typeof window === "undefined") return
  try {
    window.localStorage.setItem(I18N_STORAGE_KEY, locale)
  } catch {
    // ignore
  }
}

async function loadLocale(locale: LocaleCode): Promise<{ messages: MessageDict; phrases: PhrasesMap }> {
  // Dynamic import to keep bundles small per locale
  const mod = locale === "zh-CN"
    ? await import("@jjk/locales/zh-CN.json")
    : await import("@jjk/locales/en.json")
  const data = (mod as any).default as Record<string, unknown>
  const { __phrases = {}, ...rest } = data as { __phrases?: PhrasesMap }
  const messages: MessageDict = {}
  for (const k of Object.keys(rest)) {
    const v = (rest as any)[k]
    if (typeof v === "string") messages[k] = v
  }
  return { messages, phrases: __phrases as PhrasesMap }
}

export function I18nProvider({ children }: { children: React.ReactNode }) {
  // 确保首屏 SSR 与客户端第一次渲染一致：默认使用 zh-CN
  const initialParsed = (() => {
    const data = zhCNRaw as unknown as Record<string, unknown> & { __phrases?: PhrasesMap }
    const { __phrases = {}, ...rest } = data
    const msgs: MessageDict = {}
    for (const k of Object.keys(rest)) {
      const v = (rest as any)[k]
      if (typeof v === "string") msgs[k] = v
    }
    return { msgs, phr: __phrases as PhrasesMap }
  })()

  const [locale, setLocaleState] = useState<LocaleCode>("zh-CN")
  const [messages, setMessages] = useState<MessageDict>(initialParsed.msgs)
  const [phrases, setPhrases] = useState<PhrasesMap>(initialParsed.phr)

  useEffect(() => {
    let mounted = true
    loadLocale(locale).then(({ messages: dict, phrases: ph }) => {
      if (!mounted) return
      setMessages(dict)
      setPhrases(ph)
    })
    return () => {
      mounted = false
    }
  }, [locale])

  // 挂载后再应用本地存储的语言，避免首屏水合不一致
  useEffect(() => {
    const stored = loadStoredLocale()
    if (stored === "en") {
      setLocaleState("en")
      if (typeof document !== "undefined") {
        document.documentElement.lang = "en"
      }
    }
  }, [])

  // DOM 级别的兜底翻译：短语级替换 + 监听异步变更
  useEffect(() => {
    if (typeof window === "undefined") return
    const raw = phrases || {}
    const phraseMap: Record<string, string> = locale === "en" ? raw : invertMap(raw)

    const ignoredTags = new Set(["SCRIPT", "STYLE", "NOSCRIPT", "CODE", "PRE", "TEXTAREA"])

    const escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")

    const sortedKeys = Object.keys(phraseMap).sort((a, b) => b.length - a.length)
    const keyRegexes = sortedKeys.map((k) => ({ key: k, rx: new RegExp(escapeRegExp(k), "g") }))

    const translateText = (text: string): string => {
      if (!text) return text
      let result = text
      for (const { key, rx } of keyRegexes) {
        const val = phraseMap[key]
        if (!val) continue
        result = result.replace(rx, val)
      }
      return result
    }

    const translateNode = (node: Node) => {
      if (node.nodeType === Node.TEXT_NODE) {
        const t = node as Text
        const oldVal = t.nodeValue || ""
        const newVal = translateText(oldVal)
        if (newVal !== oldVal) t.nodeValue = newVal
        return
      }
      if (!(node instanceof Element)) return
      if (ignoredTags.has(node.tagName)) return
      if (node.hasAttribute("data-i18n-ignore")) return
      for (const child of Array.from(node.childNodes)) translateNode(child)
    }

    const translateDocument = () => {
      if (!document.body) return
      translateNode(document.body)
    }

    // 初始翻译
    translateDocument()

    // 监听动态变更
    const observer = new MutationObserver((mutations) => {
      for (const m of mutations) {
        if (m.type === "characterData" && m.target) {
          translateNode(m.target)
        }
        if (m.type === "childList") {
          m.addedNodes.forEach((n) => translateNode(n))
        }
      }
    })
    observer.observe(document.body, {
      subtree: true,
      childList: true,
      characterData: true
    })

    return () => observer.disconnect()
  }, [phrases, locale])

  const setLocale = useCallback((lc: LocaleCode) => {
    setLocaleState(lc)
    saveStoredLocale(lc)
    if (typeof document !== "undefined") {
      document.documentElement.lang = lc === "zh-CN" ? "zh-CN" : "en"
    }
  }, [])

  const t = useCallback(
    (key: string, fallback?: string) => {
      if (messages && Object.prototype.hasOwnProperty.call(messages, key)) {
        return messages[key]
      }
      return fallback ?? key
    },
    [messages]
  )

  const value = useMemo<I18nContextValue>(
    () => ({ locale, setLocale, t, messages }),
    [locale, setLocale, t, messages]
  )

  return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>
}

export function useI18n() {
  const ctx = useContext(I18nContext)
  if (!ctx) throw new Error("useI18n must be used within I18nProvider")
  return ctx
}

export function LanguageSwitcher() {
  const { locale, setLocale } = useI18n()
  
  const toggleLanguage = () => {
    const newLocale = locale === "zh-CN" ? "en" : "zh-CN"
    setLocale(newLocale)
  }
  
  return (
    <button
      type="button"
      onClick={toggleLanguage}
      className="inline-flex h-8 items-center justify-center gap-2 rounded-md border border-input bg-background px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
      title={locale === "zh-CN" ? "切换到英文" : "Switch to Chinese"}
    >
      <span className="text-xs">🌐</span>
      <span>
        {locale === "zh-CN" ? "中文" : "EN"}
      </span>
    </button>
  )
}

export type { LocaleCode, MessageDict, I18nResources }

function invertMap(map: Record<string, string>): Record<string, string> {
  const result: Record<string, string> = {}
  for (const k of Object.keys(map)) {
    const v = map[k]
    if (v != null && result[v] == null) {
      result[v] = k
    }
  }
  return result
}

